<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>SimpleTrace | Performance Insights</title>
  <script src="https://cdn.bootcdn.net/ajax/libs/mermaid/11.5.0/mermaid.min.js"></script>
  <script src="https://cdn.bootcdn.net/ajax/libs/jquery.panzoom/4.0.0/panzoom.min.js"></script>
  <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
  <link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap" rel="stylesheet">
  <style>
    :root {
      --primary: #6f42c1;
      --primary-light: #8a63d2;
      --secondary: #f8f9fa;
      --dark: #1a1a1a;
      --light: #ffffff;
      --gray: #6c757d;
      --gray-light: #e9ecef;
      --success: #28a745;
      --danger: #dc3545;
      --warning: #ffc107;
      --info: #17a2b8;
      --border-radius: 12px;
      --box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
      --transition: all 0.3s ease;
    }

    * {
      margin: 0;
      padding: 0;
      box-sizing: border-box;
    }

    body {
      font-family: 'Inter', sans-serif;
      background-color: #f5f7fa;
      color: var(--dark);
      line-height: 1.6;
      padding: 0;
    }

    .container {
      max-width: 80%;
      margin: 0 auto;
      padding: 0 20px;
    }

    /* Header */
    header {
      background-color: var(--light);
      box-shadow: var(--box-shadow);
      padding: 1rem 0;
      position: sticky;
      top: 0;
      z-index: 100;
    }

    .header-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .logo {
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .logo i {
      color: var(--primary);
      font-size: 1.8rem;
    }

    .logo h1 {
      font-size: 1.5rem;
      font-weight: 700;
      color: var(--dark);
    }

    .header-actions {
      display: flex;
      gap: 15px;
    }

    .btn {
      padding: 0.5rem 1rem;
      border-radius: var(--border-radius);
      font-weight: 500;
      cursor: pointer;
      transition: var(--transition);
      border: none;
      display: inline-flex;
      align-items: center;
      gap: 8px;
    }

    .btn-primary {
      background-color: var(--primary);
      color: var(--light);
    }

    .btn-primary:hover {
      background-color: var(--primary-light);
      transform: translateY(-2px);
    }

    .btn-outline {
      background-color: transparent;
      border: 1px solid var(--gray-light);
      color: var(--dark);
    }

    .btn-outline:hover {
      background-color: var(--gray-light);
    }

    /* Search Bar */
    .search-bar {
      background-color: var(--light);
      padding: 1.5rem 0;
      border-bottom: 1px solid var(--gray-light);
      margin-bottom: 1rem;
    }

    .search-container {
      display: flex;
      gap: 10px;
      max-width: 800px;
      margin: 0 auto;
    }

    .search-input {
      flex: 1;
      padding: 0.75rem 1rem;
      border: 1px solid var(--gray-light);
      border-radius: var(--border-radius);
      font-size: 1rem;
      transition: var(--transition);
    }

    .search-input:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 2px rgba(111, 66, 193, 0.2);
    }

    .search-btn {
      padding: 0.75rem 1.5rem;
    }


    /* Main Content */
    main {
      padding: 2rem 0;
    }

    .dashboard {
      display: grid;
      grid-template-columns: 1fr;
      gap: 2rem;
    }

    .card {
      background-color: var(--light);
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      overflow: hidden;
      transition: var(--transition);
    }

    .card:hover {
      box-shadow: 0 8px 25px rgba(0, 0, 0, 0.12);
    }

    .card-header {
      padding: 1.2rem 1.5rem;
      border-bottom: 1px solid var(--gray-light);
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .card-title {
      font-size: 1.2rem;
      font-weight: 600;
      color: var(--dark);
      display: flex;
      align-items: center;
      gap: 10px;
    }

    .card-title i {
      color: var(--primary);
    }

    .card-actions {
      display: flex;
      gap: 10px;
    }

    .card-body {
      padding: 1.5rem;
    }

    /* Trace Visualization */
    .trace-visualization {
      position: relative;
      height: 600px;
    }

      /* Trace Visualization */
      .mermaid-container-wrapper {
        position: relative;
        width: 100%;
        height: 600px;
        overflow: hidden;
        background: var(--light);
        border-radius: var(--border-radius);
        border: 1px solid var(--gray-light);
      }

      .mermaid {
        display: flex;
        justify-content: center;
        align-items: center;
        width: 100%;
        height: 100%;
        padding: 1rem;
      }

      .mermaid svg {
        max-width: 100%;
        max-height: 100%;
        display: block;
        margin: 0 auto;
      }

      .slide-panel-overlay {
      position: fixed;
      top: 0;
      left: 0;
      right: 0;
      bottom: 0;
      background-color: rgba(0, 0, 0, 0.5);
      z-index: 1000;
      opacity: 0;
      visibility: hidden;
      transition: var(--transition);
    }

    .slide-panel-overlay.active {
      opacity: 1;
      visibility: visible;
    }

    /* Trace Details */
    .trace-detail {
      position: fixed;
      top: 0;
      right: -650px;
      width: 650px;
      height: 100vh;
      background-color: var(--light);
      box-shadow: -5px 0 15px rgba(0, 0, 0, 0.1);
      z-index: 1001;
      transition: right 0.3s ease;
      overflow-y: auto;
      display: flex;
      flex-direction: column;
    }

    .trace-detail.active {
      right: 0;
    }

    .panel-header {
      padding: 1.2rem 1.5rem;
      border-bottom: 1px solid var(--gray-light);
      display: flex;
      justify-content: space-between;
      align-items: center;
      background-color: var(--primary);
      color: white;
    }

    .panel-header h3 {
      font-weight: 600;
    }

    .close-panel {
      background: none;
      border: none;
      color: white;
      font-size: 1.2rem;
      cursor: pointer;
      transition: var(--transition);
    }

    .close-panel:hover {
      transform: scale(1.1);
    }

    .panel-body {
      flex: 1;
      overflow-y: auto;
      padding-bottom: 1rem;
    }

    .detail-section {
      padding: 1.5rem;
      border-bottom: 1px solid var(--gray-light);
    }

    .detail-section:last-child {
      border-bottom: none;
    }

    .detail-label {
      font-size: 0.9rem;
      font-weight: 600;
      color: var(--gray);
      margin-bottom: 0.5rem;
      text-transform: uppercase;
      letter-spacing: 0.5px;
    }

    .detail-value {
      font-size: 1rem;
      color: var(--dark);
      font-weight: 500;
    }

    .json-viewer {
      background-color: #f8f9fa;
      padding: 1rem;
      border-radius: 8px;
      font-family: 'Courier New', Courier, monospace;
      font-size: 0.9rem;
      overflow-x: auto;
      margin-top: 0.5rem;
      border: 1px solid var(--gray-light);
    }

    /* Stats */
    .stats-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
      gap: 1.5rem;
      margin-bottom: 2rem;
    }

    .stat-card {
      background-color: var(--light);
      border-radius: var(--border-radius);
      padding: 1.5rem;
      box-shadow: var(--box-shadow);
      text-align: center;
    }

    .stat-value {
      font-size: 2rem;
      font-weight: 700;
      color: var(--primary);
      margin-bottom: 0.5rem;
    }

    .stat-label {
      font-size: 0.9rem;
      color: var(--gray);
    }

    /* Footer */
    footer {
      background-color: var(--dark);
      color: var(--light);
      padding: 2rem 0;
      margin-top: 3rem;
    }

    .footer-content {
      display: flex;
      justify-content: space-between;
      align-items: center;
    }

    .footer-links {
      display: flex;
      gap: 1.5rem;
    }

    .footer-links a {
      color: var(--light);
      text-decoration: none;
      transition: var(--transition);
    }

    .footer-links a:hover {
      color: var(--primary-light);
    }

    .copyright {
      font-size: 0.9rem;
      color: var(--gray);
    }

    /* Responsive */
    @media (max-width: 768px) {
      .header-content {
        flex-direction: column;
        gap: 1rem;
      }

      .stats-grid {
        grid-template-columns: 1fr;
      }
    }

/* Filter Form */
    .filter-form {
      background-color: var(--light);
      padding: 1.5rem;
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      margin-bottom: 1.5rem;
    }

    .filter-title {
      font-size: 1.1rem;
      font-weight: 600;
      margin-bottom: 1rem;
      color: var(--dark);
      display: flex;
      align-items: center;
      gap: 8px;
    }

    .filter-title i {
      color: var(--primary);
    }

    .filter-grid {
      display: grid;
      grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
      gap: 1rem;
    }

    .filter-group {
      display: flex;
      flex-direction: column;
      gap: 0.5rem;
    }

    .filter-label {
      font-size: 0.9rem;
      color: var(--gray);
      font-weight: 500;
    }

    .filter-control {
      display: flex;
      gap: 0.5rem;
    }

    .filter-input {
      flex: 1;
      padding: 0.5rem 0.75rem;
      border: 1px solid var(--gray-light);
      border-radius: var(--border-radius);
      font-size: 0.9rem;
      transition: var(--transition);
    }

    .filter-input:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 2px rgba(111, 66, 193, 0.2);
    }

    .filter-select {
      flex: 1;
      padding: 0.5rem 0.75rem;
      border: 1px solid var(--gray-light);
      border-radius: var(--border-radius);
      font-size: 0.9rem;
      background-color: var(--light);
      transition: var(--transition);
    }

    .filter-select:focus {
      outline: none;
      border-color: var(--primary);
      box-shadow: 0 0 0 2px rgba(111, 66, 193, 0.2);
    }

    .filter-btn {
      padding: 0.5rem 1rem;
      white-space: nowrap;
    }

    .filter-reset {
      margin-top: 1rem;
      display: flex;
      justify-content: flex-end;
    }

    .trace-time-info {
      position: absolute;
      top: 15px;
      left: 20px;
      background-color: rgba(255, 255, 255, 0.9);
      padding: 0.5rem 1rem;
      border-radius: var(--border-radius);
      box-shadow: var(--box-shadow);
      z-index: 10;
      display: flex;
      align-items: center;
      gap: 8px;
      font-size: 0.9rem;
      color: var(--gray);
      border: 1px solid var(--gray-light);
    }

    .trace-time-info i {
      color: var(--primary);
    }
  </style>
</head>
<body>
  <header>
    <div class="container">
      <div class="header-content">
        <div class="logo">
          <i class="fas fa-project-diagram"></i>
          <h1>SimpleTrace</h1>
        </div>
        <div class="header-actions">
          <button class="btn btn-outline" id="exportBtn">
            <i class="fas fa-download"></i> Export
          </button>
          <button class="btn btn-primary">
            <i class="fas fa-cog"></i> Settings
          </button>
        </div>
      </div>
    </div>
  </header>


    <!-- 新增搜索栏 -->
    <div class="search-bar">
      <div class="container">
        <div class="search-container">
          <input
            type="text"
            id="traceIdSearch"
            class="search-input"
            placeholder="Enter Trace ID to search..."
            aria-label="Search Trace ID"
          />
          <button id="searchBtn" class="btn btn-primary search-btn">
            <i class="fas fa-search"></i> Search
          </button>
        </div>
      </div>
    </div>

  <main>
    <div class="container">
      <div class="dashboard">
        <!-- Stats Overview -->
        <div class="stats-grid">
          <div class="stat-card">
            <div class="stat-value" id="total-spans">0</div>
            <div class="stat-label">Total Spans</div>
          </div>
          <div class="stat-card">
            <div class="stat-value" id="total-duration">0ms</div>
            <div class="stat-label">Total Duration</div>
          </div>
          <div class="stat-card">
            <div class="stat-value" id="avg-duration">0ms</div>
            <div class="stat-label">Avg Duration</div>
          </div>
          <div class="stat-card">
            <div class="stat-value" id="max-duration">0ms</div>
            <div class="stat-label">Max Duration</div>
          </div>
        </div>

        <div class="filter-form">
          <h3 class="filter-title">
            <i class="fas fa-filter"></i> Filter Options
          </h3>
          <div class="filter-grid">
            <div class="filter-group">
              <label class="filter-label">Hide nodes with duration less than (ms)</label>
              <div class="filter-control">
                <input type="number" id="durationThreshold" class="filter-input" placeholder="e.g. 50" min="0">

              </div>
            </div>
            <div class="filter-group">
              <label class="filter-label">Filter by function name (regex)</label>
              <div class="filter-control">
                <input type="text" id="functionNameFilter" class="filter-input" placeholder="e.g. ^Get.*">

              </div>
            </div>

            <div class="filter-group">
              <label class="filter-label">Filter by service</label>
              <div class="filter-control">
                <select id="serviceFilter" class="filter-select">
                  <option value="">All Services</option>
                  <option value="logic">logic</option>
                  <option value="chatmsg">chatmsg</option>
                  <option value="identity">identity</option>
                  <option value="admin">admin</option>
                  <option value="app">app</option>
                  <option value="job">job</option>
                  <option value="meeting">meeting</option>
                  <option value="searchsys">searchsys</option>
                </select>

              </div>
            </div>
          </div>
          <div class="filter-reset">
            <button class="btn btn-outline" id="filterSubmit">
              <i class="fas fa-search"></i>Submit</button>
            <button class="btn btn-outline" id="resetFilters">
              <i class="fas fa-undo"></i> Reset </button>
          </div>
        </div>

        <!-- Trace Visualization -->
        <div class="card">
          <div class="card-header">
            <h2 class="card-title">
              <i class="fas fa-code-branch"></i> Trace Visualization
            </h2>
            <div class="card-actions">
              <button class="btn btn-outline" id="zoom-in">
                <i class="fas fa-search-plus"></i>
              </button>
              <button class="btn btn-outline" id="zoom-out">
                <i class="fas fa-search-minus"></i>
              </button>
              <button class="btn btn-outline" id="reset-zoom">
                <i class="fas fa-expand"></i>
              </button>           
            </div>
          </div>      
          <div class="card-body">            
              <div class="mermaid-container-wrapper">
                <div class="trace-time-info">
                  <i class="fas fa-clock"></i>
                  <span id="traceTime">2025-07-04 10:00:00</span>
                </div>              
                <div class="mermaid" id="mermaid-container">
graph TD              
{{.MermaidGraph}}
                </div>
              </div>
          </div>
        </div>

        <div class="slide-panel-overlay" id="panelOverlay"></div>
        <!-- Trace Details -->
        <div class="trace-detail" id="detail">
          <div class="panel-header">
            <h3>Span Details</h3>
            <button class="close-panel" id="closePanel">
              <i class="fas fa-times"></i>
            </button>
          </div>
          <div class="panel-body">
            <div class="detail-section">
              <div class="detail-label">Service</div>
              <div class="detail-value" id="serviceName">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Region</div>
              <div class="detail-value" id="regionName">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Function</div>
              <div class="detail-value" id="funcName">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Position</div>
              <div class="detail-value" id="funcPos">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Span ID</div>
              <div class="detail-value" id="spanId">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Duration</div>
              <div class="detail-value" id="duration">-</div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Children</div>
              <div class="detail-value" id="children">-</div>
              </div>
              <div class="detail-section">
              <div class="detail-label">Arguments</div>
              <div class="json-container">
                <button class="copy-btn" onclick="copyToClipboard('argsJson', this)">
                  <i class="far fa-copy"></i> Copy
                </button>
                <pre class="json-viewer" id="argsJson">{}</pre>
              </div>
            </div>
            <div class="detail-section">
              <div class="detail-label">Returns</div>
              <div class="json-container">
                <button class="copy-btn" onclick="copyToClipboard('returnsJson', this)">
                  <i class="far fa-copy"></i> Copy
                </button>
                <pre class="json-viewer" id="returnsJson">{}</pre>
              </div>
            </div>
          </div>
        </div>
      </div>
    </div>
  </main>

  <footer>
    <div class="container">
      <div class="footer-content">
        <div class="logo">
          <i class="fas fa-project-diagram"></i>
          <h2>SimpleTrace</h2>
        </div>
        <div class="footer-links">
          <a href="#">Documentation</a>
          <a href="#">GitHub</a>
          <a href="#">Contact</a>
        </div>
        <div class="copyright">
          &copy; 2025 SimpleTrace by cg33. All rights reserved.
        </div>
      </div>
    </div>
  </footer>
<style>
  /* 添加复制按钮样式 */
  .copy-btn {
    position: absolute;
    top: 10px;
    right: 10px;
    background: #8d78b3;
    color: white;
    border: none;
    border-radius: 4px;
    padding: 4px 8px;
    cursor: pointer;
    font-size: 0.8rem;
    display: flex;
    align-items: center;
    gap: 4px;
    transition: var(--transition);
  }
  
  .copy-btn:hover {
    background: var(--primary-light);
  }
  
  .copy-btn i {
    font-size: 0.7rem;
  }
  
  .copy-success {
    background: #3b3643 !important;
  }
  
  .detail-section {
    position: relative;
    padding: 1.5rem;
    border-bottom: 1px solid var(--gray-light);
  }
  
  .json-container {
    position: relative;
  }
</style>

<script>
  // 复制到剪贴板函数
  function copyToClipboard(elementId, button) {
    const element = document.getElementById(elementId);
    const textToCopy = element.textContent;
    
    navigator.clipboard.writeText(textToCopy).then(() => {
      // 复制成功反馈
      const originalText = button.innerHTML;
      button.innerHTML = '<i class="fas fa-check"></i> Copied';
      button.classList.add('copy-success');
      
      // 2秒后恢复原状
      setTimeout(() => {
        button.innerHTML = originalText;
        button.classList.remove('copy-success');
      }, 2000);
    }).catch(err => {
      console.error('Failed to copy text: ', err);
      alert('Failed to copy text. Please try again.');
    });
  }
  
  // 为所有可复制内容添加按钮 (动态添加)
  function addCopyButtons() {
    const jsonContainers = document.querySelectorAll('.json-container');
    
    jsonContainers.forEach(container => {
      // 检查是否已有按钮
      if (!container.querySelector('.copy-btn')) {
        const preElement = container.querySelector('pre');
        if (preElement) {
          const elementId = preElement.id;
          const copyBtn = document.createElement('button');
          copyBtn.className = 'copy-btn';
          copyBtn.innerHTML = '<i class="far fa-copy"></i> Copy';
          copyBtn.onclick = function() { copyToClipboard(elementId, this); };
          container.insertBefore(copyBtn, preElement);
        }
      }
    });
  }
  
  // 页面加载完成后添加复制按钮
  window.addEventListener('load', addCopyButtons);
</script>
  <script>

        function zoomToFit() {
        if (!panzoomInstance) return;
        const container = document.querySelector(".mermaid-container-wrapper");
        const svg = document.querySelector("#mermaid-container svg");
        if (panzoomInstance.zoomToFit) {
          panzoomInstance.zoomToFit({ scale: 0.9 });
        } else {
          // 回退方案
          const scale = Math.min(
            (container.clientWidth / svg.scrollWidth) * 0.9,
            (container.clientHeight / svg.scrollHeight) * 0.9
          );
          panzoomInstance.zoom(scale);
        }
      }

      function analyzeMermaidDurations(mermaidCode) {
        const durationRegex = /<br>([\d.]+)(ms|s)/g;
        const durations = [];

        for (const line of mermaidCode.split('\n')) {
          let match;
          while ((match = durationRegex.exec(line)) !== null) {
            const value = parseFloat(match[1]);
            const unit = match[2];
            const ms = unit === 's' ? value * 1000 : value;
            durations.push(ms);
          }
        }

        const totalSpans = durations.length;
        const totalDuration = Math.max(...durations);
        const avgDuration = totalSpans ? totalDuration / totalSpans : 0;

        // ❗ maxDuration 忽略第一个节点
        const maxDuration = durations.length > 1
          ? Math.max(...durations.slice(1))
          : 0;

        return {
          totalSpans,
          totalDuration,
          avgDuration,
          maxDuration
        };
      }

    let metas = analyzeMermaidDurations(document.querySelector("#mermaid-container").innerHTML);

    function downloadSVG(svgElement, filename = "graph.svg") {
      const serializer = new XMLSerializer();
      const svgContent = serializer.serializeToString(svgElement);

      const blob = new Blob([svgContent], { type: "image/svg+xml;charset=utf-8" });
      const url = URL.createObjectURL(blob);

      const link = document.createElement("a");
      link.href = url;
      link.download = filename;
      link.click();

      URL.revokeObjectURL(url);
    }

    // 导出原始GET请求获取的HTML
    async function exportOriginalHTML() {
      try {
        // 获取当前页面的URL
        const apiUrl = window.location.href;
        
        // 从URL中获取trace_id参数
        const urlParams = new URLSearchParams(window.location.search);
        const traceId = urlParams.get('trace_id') || 'trace_report';
        
        // 获取原始HTML内容
        const originalHTML = await fetchOriginalHTML(apiUrl);
        
        // 创建Blob对象
        const blob = new Blob([originalHTML], { type: 'text/html' });
        
        // 创建下载链接
        const url = URL.createObjectURL(blob);
        const a = document.createElement('a');
        a.href = url;
        a.download = `${traceId}.html`;
        
        // 触发下载
        document.body.appendChild(a);
        a.click();
        
        // 清理
        setTimeout(() => {
          document.body.removeChild(a);
          URL.revokeObjectURL(url);
        }, 100);
      } catch (error) {
        console.error('导出失败:', error);
        alert('导出HTML失败: ' + error.message);
      }
    }

    // 获取原始HTML内容的函数
    async function fetchOriginalHTML(url) {
      const response = await fetch(url, {
        method: 'GET',
        headers: {
          'Accept': 'text/html'
        }
      });
      
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      
      return await response.text();
    }

    function pathToGitUrl(inputPath, service) {
      const baseUrls = {
        logic: "https://ksogit.kingsoft.net/chat/kim/-/blob/private_test",
        admin: "https://ksogit.kingsoft.net/chat/admin/-/blob/private_test",
        identity: "https://ksogit.kingsoft.net/chat/identity/-/blob/private_test",
        chatmsg: "https://ksogit.kingsoft.net/kim/chatmsg/-/blob/private_test",
        meeting: "https://ksogit.kingsoft.net/chat/meeting/-/blob/private_test",
        app: "https://ksogit.kingsoft.net/chat/app/-/blob/private_test",
        job: "https://ksogit.kingsoft.net/chat/kim/-/blob/private_test",
        searchsys: "https://ksogit.kingsoft.net/chat/kim-search/searchsys/-/blob/private_test"
      };

      const baseUrl = baseUrls[service];
      if (!baseUrl) {
        throw new Error(`Unknown service: ${service}`);
      }

      const match = inputPath.match(/^(?:\/build-dir)?(\/.+):(\d+)$/);
      if (!match) {
        throw new Error("Invalid input format");
      }

      const filePath = match[1];
      const lineNumber = match[2];

      return `${baseUrl}${filePath}?ref_type=heads#L${lineNumber}`;
    }    

    // Initialize Mermaid
    mermaid.initialize({
      startOnLoad: true,
      securityLevel: "loose",
      theme: "default",
      flowchart: {
        useMaxWidth: false,
        htmlLabels: true,
        curve: "basis"
      }
    });

    // Panzoom functionality
    let panzoomInstance;
    window.addEventListener('load', () => {
      setTimeout(() => {
        const svg = document.querySelector(".mermaid svg");
        if (svg) {
          panzoomInstance = Panzoom(svg, {
            zoomEnabled: true,
            maxScale: 8,
            minScale: 0.5,
          });

          const container = document.getElementById("mermaid-container");
          container.addEventListener("wheel", panzoomInstance.zoomWithWheel);

          // Zoom controls
          document.getElementById('zoom-in').addEventListener('click', () => {
            panzoomInstance.zoomIn();
          });
          
          document.getElementById('zoom-out').addEventListener('click', () => {
            panzoomInstance.zoomOut();
          });
          
          document.getElementById('reset-zoom').addEventListener('click', () => {
            panzoomInstance.reset();
          });

          // 从 url 获取参数初始化筛选表单
          const urlParams = new URLSearchParams(window.location.search);
          const durationThreshold = urlParams.get('min_dur_ms') || '';
          const functionNameFilter = urlParams.get('func_name_regex') || '';
          const serviceFilter = urlParams.get('filter_svc') || '';
          document.getElementById('durationThreshold').value = durationThreshold;
          document.getElementById('functionNameFilter').value = functionNameFilter;
          document.getElementById('serviceFilter').value = serviceFilter;

          document.getElementById('filterSubmit').addEventListener('click', () => {
              const urlParams = new URLSearchParams(window.location.search);
              urlParams.delete('min_dur_ms');
              urlParams.delete('hide_zero_span');
              urlParams.delete('func_name_regex');
              urlParams.delete('filter_svc');
              const traceId = urlParams.get('trace_id');
              if (traceId) {
                urlParams.set('trace_id', traceId);
              }
              finalurl = window.location.pathname + '?' + urlParams.toString();
              const threshold = parseInt(document.getElementById('durationThreshold').value, 10);
              if (threshold == 0) {
                finalurl = finalurl + "&hide_zero_span=1";
              } else {
                finalurl = finalurl + "&min_dur_ms=" + threshold;               
              }
              const regex = document.getElementById('functionNameFilter').value.trim();
              if (regex) {
                finalurl = finalurl + "&func_name_regex=" + encodeURIComponent(regex);
              }
              const service = document.getElementById('serviceFilter').value;
              if (service) {
                finalurl = finalurl + "&filter_svc=" + encodeURIComponent(service);
              }
              if (finalurl != window.location.href) {
                window.location.href = finalurl;
              }
          });

          document.getElementById('resetFilters').addEventListener('click', () => {
              document.getElementById('durationThreshold').value = '';
              document.getElementById('functionNameFilter').value = '';
              document.getElementById('serviceFilter').value = '';
              // 保留trace_id参数，清除其他参数
              const urlParams = new URLSearchParams(window.location.search);
              urlParams.delete('min_dur_ms');
              urlParams.delete('hide_zero_span');
              urlParams.delete('func_name_regex');
              urlParams.delete('filter_svc');
              const traceId = urlParams.get('trace_id');
              if (traceId) {
                urlParams.set('trace_id', traceId);
              }
              const newUrl = window.location.pathname + '?' + urlParams.toString();
              window.location.href = newUrl;
          });

          zoomToFit();
        }
      }, 1000);

        document.getElementById('traceTime').textContent = traceInfo['start_time'] || 'N/A';

      // Simulate loading some stats (in a real app, this would come from your data)
        document.getElementById('total-spans').textContent = metas.totalSpans;
        document.getElementById('total-duration').textContent = `${metas.totalDuration/1000}s`;
        document.getElementById('avg-duration').textContent = `${metas.avgDuration.toFixed(2)}ms`;
        document.getElementById('max-duration').textContent = `${metas.maxDuration}ms`;
        console.log("Trace Meta:", metas);

        // 监听导出事件
        document.getElementById('exportBtn').addEventListener('click', () => {
          // const svgElement = document.querySelector(".mermaid svg");
          // if (svgElement) {
          //   downloadSVG(svgElement, "trace-visualization.svg");
          // } else {
          //   alert("No SVG found to export.");
          // }
          exportOriginalHTML();
        });        
    });

    // Function to show trace details
    function showDetail(spanId) {
      const info = traceMeta[spanId];
      if (!info) return;

       // 设置 a 标签内容
      const funcPos = document.getElementById("funcPos");
      if (info.pos) {
        const url = pathToGitUrl(info.pos, info.svc);
        funcPos.innerHTML = `<a href="${url}" target="_blank" rel="noopener noreferrer">${info.pos}</a>`;
      } else {
        funcPos.textContent = '-';
      }

      if (spanId) {
        const urlParams = new URLSearchParams(window.location.search);
        urlParams.delete('from_span_id');
        urlParams.set('from_span_id', spanId);
        const newUrl = window.location.pathname + '?' + urlParams.toString();
        // 设置spanId的内容
        document.getElementById("spanId").innerHTML = `<a href="${newUrl}" target="_blank" rel="noopener noreferrer">${spanId}</a>`;
      } else {
        document.getElementById("spanId").textContent = '-';
      }
      
      // Update detail fields
      document.getElementById("serviceName").textContent = info.svc || '-';
      document.getElementById("regionName").textContent = info.region || '-';
      document.getElementById("funcName").textContent = info.name || '-';
      document.getElementById("duration").textContent = info.duration ? `${info.duration}` : '-';
    
      document.getElementById("argsJson").textContent = JSON.stringify(info.args || {}, null, 2);
      document.getElementById("returnsJson").textContent = JSON.stringify(info.returns || {}, null, 2);

      // 显示子节点信息
      const spaninfo = spanInfos[spanId];
      if (spaninfo) {
        const childrenList = document.getElementById("children");
        childrenList.innerHTML = ''; // 清空之前的内容
        if (spaninfo.children) {
          spaninfo.children.forEach(child => {
            const childSpanId = child.span_id;
            const childSpanName = child.name || 'Unknown';
            const childUrlParams = new URLSearchParams(window.location.search);
            childUrlParams.delete('from_span_id');
            childUrlParams.set('from_span_id', childSpanId);
            const childUrl = window.location.pathname + '?' + childUrlParams.toString();
            const listItem = document.createElement("li");
            listItem.innerHTML = `<a href="${childUrl}" target="_blank" rel="noopener noreferrer">${childSpanId}</a><span style="margin-left: 10px;">${childSpanName}</span>`;
            childrenList.appendChild(listItem);
          });
        } else {
          document.getElementById("children").textContent = '-';
        }
      } else {
        document.getElementById("children").textContent = '-';
      }
      
      // 显示面板和遮罩
      document.getElementById('detail').classList.add('active');
      document.getElementById('panelOverlay').classList.add('active');

      // Show detail panel with animation
      const detailPanel = document.getElementById("detail");
      detailPanel.classList.add("active");
      
      // Scroll to detail panel
      setTimeout(() => {
        detailPanel.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
      }, 100);
    }

    function hideDetail() {
      document.getElementById('detail').classList.remove('active');
      document.getElementById('panelOverlay').classList.remove('active');
    }

    // 事件监听
    document.getElementById('closePanel').addEventListener('click', hideDetail);
    document.getElementById('panelOverlay').addEventListener('click', hideDetail);

    document.getElementById("searchBtn").addEventListener("click", () => {
      const traceId = document.getElementById("traceIdSearch").value.trim();
      // 获取当前浏览器的url，去掉query参数
        const currentUrl = window.location.href.split("?")[0];
        // 跳转到对应的span详情
        window.location.href = `${currentUrl}?trace_id=${traceId}`;
    });

    // In a real app, you would have some traceMeta data
    // This is just a placeholder for demonstration
    // eslint-disable-next-line no-unused-vars
    const traceMeta = {{.TraceMeta}}
    const traceInfo = {{.TraceInfo}}
    const spanInfos = {{.SpanInfos}}
  </script>
</body>
</html>